#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <time.h>

// 注意学习C语言中位域的写法和含义
struct LedRegister {
    unsigned onoff:  2; // 2 bit控制LED开关
    unsigned status: 4; // 4 bit控制状态
    unsigned reserve:2; // 2 bit预留
};

// 注意C语言中结构体的内存对齐
// 同样类型的3个字段，排列顺序不同，占用空间也不同
// 内存对齐是空间换时间的算法，目的是减少CPU访问结构体字段时读取内存的次数
// 注意结构体中每个字段偏移量的规则：
// 1. 首字段偏移量0
// 2. 其他字段的偏移量取min(字段长度, 对齐系数)的整数倍
// 3. 结构体本身也要对齐，取min(结构体字段最大长度, 对齐系数)的整数倍
// 注意注释中的[]表示内存字节，数字代表偏移量
struct A {
    char ch;  // [0]
              // [1] [2] [3]   // 根据规则2，字段i前面补充3个字节
    int  i;   // [4] [5] [6] [7]
    double d; // [8] [9] [10] [11] [12] [13] [14] [15]
};

struct B {
    int i;      // [0] [1] [2] [3]
                // [4] [5] [6] [7] // 根据规则2，补充4个字节
    double d;   // [8] [9] [10] [11] [12] [13] [14] [15]
    char ch;    // [16]
                // 总共17个字节，根据规则3，在8字节对齐情况下，取距17最近的8的整数倍，最终24字节
};

// 注意，可以用pragma pack指定对齐系数
// 请思考一下，在4字节对齐的情况下，下面的结构体占用多少字节。
#pragma pack(4)
struct B {
    int i;           
    double d;   
    char ch;              
};

// 注意将函数或全局变量用static修饰起来，表示该函数或全局变量仅限于本文件内部调用，从而把内部实现对外部隐藏起来
static void local_func() {
    // 用static修饰的局部变量，位于全局存储区，类似于全局变量，但可见性仅限于函数内部
    static int i = 0;
    i++;
    printf("%d\n", i);
}

int main(int argc, char** argv) {
    // time()可以获取当前时间戳（1970年1月1日0时0分0秒距今的秒数）
    time_t now = time(NULL);
    printf("%ld\n", now);
    // localtime()将时间戳转为struct tm结构，该结构体包括年月日时分秒各种数据
    // 注意struct tm结构中的月份为0-11，不是日常的1-12
    // 注意struct tm结构中的年是从1900年为基数
    struct tm* lt = localtime(&now);
    printf("%d-%d-%d %d:%d:%d\n", lt->tm_year + 1900, lt->tm_mon + 1, lt->tm_mday, lt->tm_hour, lt->tm_min, lt->tm_sec);
    // 注意用strftime可以将struct tm格式化成各种格式的字符串
    char tmstr[25];
    strftime(tmstr, 25, "%Y-%m-%d %H:%M", lt);
    printf("%s\n", tmstr);
}